/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package agents;

import jade.core.AID;
import jade.core.Agent;
//import jade.core.AgentContainer;
import jade.core.behaviours.CyclicBehaviour;
import jade.core.behaviours.TickerBehaviour;
import jade.domain.DFService;
import jade.domain.FIPAException;
import jade.lang.acl.ACLMessage;
import jade.lang.acl.MessageTemplate;
import jade.wrapper.AgentContainer;
import java.awt.Point;
import static java.lang.Math.abs;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import libPackage.CommonFunction;
import libPackage.ConstHelper;
import java.util.Random;

/**
 *
 * @author duonghau
 */
public class Animal extends Agent {

    protected float energie = ConstHelper.ENERGIE_INIT;
    protected float maxEnergie = ConstHelper.ENERGIE_MAX;
    protected float speed;// m/s
    protected Point position;// x y
    protected Point destination;// x y
    protected AID target;
    protected HashMap<AID, Point> targets;
    protected String targetType;
    protected int eatDistance;
    AgentContainer containerController;
    CommonFunction commonFunction;
    Random random = new Random();

    @Override
    protected void setup() {
        position = new Point(random.nextInt(30), random.nextInt(20));
        destination = new Point(random.nextInt(30), random.nextInt(20));
        targets = new HashMap<>();
        addBehaviours();
    }

    private void addBehaviours() {
        addBehaviour(new Move(this, 1000));
        addBehaviour(new Live(this, 1000));
        addBehaviour(new SendPosition());
        addBehaviour(new RequestDie());
        addBehaviour(new GetAllTarget(this, 1000));
        addBehaviour(new GetTargetPosition());
        addBehaviour(new Eating(this, 1000));
        addBehaviour(new SetTarget(this, 1000));
        containerController = getContainerController();
    }

    @Override
    protected void takeDown() {
        try {
            DFService.deregister(this);
        } catch (FIPAException fe) {
            fe.printStackTrace();
        }
    }

    protected class Move extends TickerBehaviour {

        public Move(Agent a, long period) {
            super(a, period);
        }

        @Override
        protected void onTick() {
            if (position.x == destination.x && position.y == destination.y) {
                if (target == null) {
                    destination = new Point(random.nextInt(30), random.nextInt(20));
                }
            } else {
                if (position.x < destination.x) {
                    position.x++;
                }
                if (position.x > destination.x) {
                    position.x--;
                }
                if (position.y < destination.y) {
                    position.y++;
                }
                if (position.y > destination.y) {
                    position.y--;
                }
            }
        }

    }

    protected class Live extends TickerBehaviour {

        public Live(Agent a, long period) {
            super(a, period);
        }

        @Override
        protected void onTick() {
            energie = energie - ConstHelper.ENERGIE_ANIMAL_LOSS;
            if (energie <= 0) {
                doDelete();
            }
        }

    }

    protected class SendPosition extends CyclicBehaviour {

        @Override
        public void action() {
            MessageTemplate messageTemplate = MessageTemplate.and(MessageTemplate.MatchPerformative(ACLMessage.CFP), MessageTemplate.MatchOntology("position"));
            ACLMessage messageQuestion = receive(messageTemplate);
            if (messageQuestion != null) {
                //reponse
                ACLMessage messageReponse = new ACLMessage(ACLMessage.INFORM);
                messageReponse.setOntology("position");
                messageReponse.addReceiver(messageQuestion.getSender());
                messageReponse.setContent(position.x + " " + position.y);
                send(messageReponse);
//                System.out.println("Receive");
            } else {
                block();
            }
        }
    }

    protected class RequestDie extends CyclicBehaviour {

        @Override
        public void action() {
            MessageTemplate messageTemplate
                    = MessageTemplate.and(MessageTemplate.MatchPerformative(ACLMessage.CFP),
                            MessageTemplate.MatchOntology("die"));
            ACLMessage receiveMessage = receive(messageTemplate);
            if (receiveMessage != null) {
                doDelete();
            } else {
                block();
            }
        }
    }

    protected class GetAllTarget extends TickerBehaviour {

        // Send message to all tree for accquiring tree position
        // PreCon: Agent is hungry
        public GetAllTarget(Agent a, long period) {
            super(a, period);
        }

        @Override
        public void onTick() {
            if (energie < ConstHelper.ENERGIE_HUNGRY) {
                ArrayList<AID> agentsTarget = commonFunction.getAgents(myAgent, targetType);
                ACLMessage messageReponse = new ACLMessage(ACLMessage.CFP);
                messageReponse.setOntology("position");
                for (AID agent : agentsTarget) {
                    messageReponse.addReceiver(agent);
                    messageReponse.setContent(ConstHelper.REQUEST_POSITION_MESSAGE);
                    send(messageReponse);
                }
            } else {
                block();
            }
        }
    }

    protected class GetTargetPosition extends CyclicBehaviour {

        // Receive all response messages of all trees
        @Override
        public void action() {
            MessageTemplate messageTemplate
                    = MessageTemplate.and(MessageTemplate.MatchPerformative(ACLMessage.INFORM),
                            MessageTemplate.MatchOntology("position"));
            ACLMessage receiveMessage = receive(messageTemplate);
            if (receiveMessage != null) {
                String[] messageContent = receiveMessage.getContent().split(" ");
                int x = Integer.parseInt(messageContent[0]);
                int y = Integer.parseInt(messageContent[1]);
                Point point = new Point(x, y);
                targets.put(receiveMessage.getSender(), point);
            } else {
                block();
            }
        }

    }

    protected class Eating extends TickerBehaviour {

        public Eating(Agent a, long period) {
            super(a, period);
        }

        @Override
        public void onTick() {
            if ((position.x == destination.x)
                    && (position.y == destination.y)
                    && (target != null)) {
                if (energie >= ConstHelper.ENERGIE_MAX) {
                    target = null;
                    targets.clear();
                    destination = new Point(random.nextInt(30), random.nextInt(20));
                } else {
                    ACLMessage messageEat = new ACLMessage(ACLMessage.CFP);
                    if (targetType.equals("plante")) {
                        messageEat.setOntology("eat");
                        messageEat.addReceiver(target);
                        messageEat.setContent("You are ate");
                        send(messageEat);
                        energie += ConstHelper.EAT_TRANFORM_ENERGIE;
                        System.out.println("I eat a tree");
                    } else {
                        messageEat.setOntology("die");
                        messageEat.addReceiver(target);
                        messageEat.setContent("You are die");
                        send(messageEat);
                        energie = ConstHelper.ENERGIE_MAX;
                        System.out.println("I eat a herbivore");
                    }
                }
//                System.out.println("Eating, energie: "+energie);

            } else {
                block();
            }
        }
    }

    protected class SetTarget extends TickerBehaviour {

        // Set target(destination) to a tree
        // PreCon: Agent is hungry
        public SetTarget(Agent a, long period) {
            super(a, period);
        }

        @Override
        public void onTick() {
            if ((energie < ConstHelper.ENERGIE_HUNGRY)
                    && (targets.size() > 0)
                    && (target == null)) {
                target = GetNearestTarget(targets);
                destination = targets.get(target);
            } else {
                block();
            }
        }
    }

    protected AID GetNearestTarget(HashMap<AID, Point> agents) {
        if (agents.size() <= 0) {
            return null;
        }
        AID nearestTarget = new AID();
        double smallestDistance = Double.POSITIVE_INFINITY;
        for (Map.Entry<AID, Point> entry : agents.entrySet()) {
            double currentDistance
                    = commonFunction.getDistance(this.position, entry.getValue());
            if (currentDistance < smallestDistance) {
                smallestDistance = currentDistance;
                nearestTarget = entry.getKey();
            }
        }
        return nearestTarget;
    }
}
